home *** CD-ROM | disk | FTP | other *** search
/ Web Designer 98 (Professional) / WebDesigner 1.0.iso / tutorials / tutorial / swish-web.txt < prev    next >
Encoding:
Text File  |  1997-06-15  |  16.9 KB  |  795 lines

  1. #!/usr/bin/perl
  2.  
  3. # swish-web.cgi
  4. # runs a SWISH search from a Web page
  5.  
  6. $SwishLocation        = "/usr/local/bin/swish";
  7. $DefaultIndexLocation    = "/usr/home/shpank/public_html/cavalcade.swish";
  8.  
  9. @MultiIndexLocation = 
  10. (
  11.   "/usr/home/shpank/public_html/cavalcade.swish",
  12.   "/usr/home/shpank/public_html/cavalcade.swish"
  13. );
  14.  
  15. $BaseDirectory          = "/usr/home/shpank/public_html/";
  16. $BaseURL                = "http://cavalcade-whimsey.com/";
  17.  
  18. $ShowFilePaths        = 1;
  19.  
  20. $PrintBoldLinks     = 1;     # this applies to page titles
  21. $HotlinkURLs        = 0;     # duplicate the hotlink on the URL line
  22. $GoofyKeyword        = "oQiTb2lkCv";
  23.  
  24. $ReturnPageURL        = "http://cavalcade-whimsey.com/index.shtml";
  25. $ReturnPagePrompt     = "The \"Cavalcade of Whimsey\"";
  26.  
  27. # edit either the simple or the detailed user form:
  28. $SwishFormURL        = "http://cavalcade-whimsey.com/index.shtml";
  29. $SwishFormPrompt    = "Search Again";
  30.  
  31. #add backslash before @ in address here ("you\@your.org")
  32. $MailtoAddress        = "shpank\@beachin.net";
  33. $MailtoPrompt        = "E-mail: ";
  34. $MailtoName        = "Shpank";
  35.  
  36. # string constants
  37. $Space                  = ' '; 
  38. $Zero                   = '0'; 
  39. $HugeFileSize           = '1000000000';
  40. $HugeTime               = '1000000000';
  41.  
  42.  
  43. #---------------------------------------------------------------------
  44. # Print Page Top
  45. #---------------------------------------------------------------------
  46.  
  47. sub PrintPageTop 
  48. {
  49. print <<ENDPRINT;
  50.  
  51. <html>
  52. <head>
  53. <title>Search Results for: $Keywords</title>
  54. </head>
  55. <body bgcolor="ffffff">
  56.  
  57. <center><table width=500>
  58. <tr><td><font size=-1>
  59. <a name="top" href="$ReturnPageURL">$ReturnPagePrompt</a><br>
  60. <a href="$SwishFormURL">$SwishFormPrompt</a>
  61. <p>
  62. Search Results for:<font size=+1 color="#000088"> $Keywords </font>
  63. <p>
  64. Remember: If you have a file that is not found here, or you would like to contribute to this
  65. database, please <a href="mailto:shpank\@beachin.net">mail</a> me. Thanks. 
  66. <hr width=85% noshade>
  67.  
  68. ENDPRINT
  69. }
  70.  
  71.  
  72. #---------------------------------------------------------------------
  73. # Print Page End
  74. #---------------------------------------------------------------------
  75.  
  76. sub PrintPageEnd
  77. {
  78.   print <<ENDPRINT;
  79.  
  80. <hr width=85% noshade>
  81. <p>
  82. If you didn't find what you were looking for, please try again.
  83. <p>
  84. <FORM METHOD="POST" 
  85. ACTION="http://cavalcade-whimsey.com/shpank/swish-web.cgi">
  86.  
  87. <input type="text" name="keywords" size="40"> 
  88. <input type="submit" value="Search">
  89. <input type="reset" value="Clear">
  90. <br>
  91. <select name="indexnumber"> 
  92. <option value="1" selected>Home 
  93. </select>
  94. <select name="maxhits">
  95. <option>10
  96. <option selected>25 
  97. <option>50
  98. <option>100
  99. <option>all
  100. </select> 
  101. Results
  102. <p>
  103. </center></form>
  104. <p>
  105. <center><a href="mailto:shpank\@beachin.net">Shpank</a>
  106.  
  107. </font>
  108. </td></tr></table></center>
  109.  
  110. </body>
  111. </html>
  112.  
  113. ENDPRINT
  114. }
  115.  
  116.  
  117. sub SetupFileTypeDescriptions
  118. {
  119.   # use " " (one space) as description to avoid displaying file type
  120.   %mimetype = (
  121.   ".html",      " ",
  122.   ".htm",       "html",
  123.   ".txt",       "plain text",
  124.   ".pdf",       "Adobe Portable Document Format",
  125.   ".ps",        "Postscript",
  126.   ".eps",       "Encapsulated Postscript",
  127.   ".rtf",       "Rich Text Format",
  128.   ".man",       "Unix manual page",
  129.   ".gif",       "GIF image",
  130.   ".jpg",       "JPEG image",
  131.   ".jpeg",      "JPEG image",
  132.   ".jpe",       "JPEG image",
  133.   ".pict",      "PICT image",
  134.   ".xbm",       "X bitmap image",
  135.   ".png",       "PNG image",
  136.   ".au",        "AU audio",
  137.   ".snd",       "Mac SND audio",
  138.   ".mpg",       "MPEG movie",
  139.   ".avi",       "MS video",
  140.   ".mov",       "QuickTime movie",
  141.   ".qt",        "QuickTime movie",
  142.   ".Z",         "Unix Z compressed",
  143.   ".gz",        "Unix gzip compressed",
  144.   ".zip",       "compressed",
  145.   ".uu",        "uuencoded",
  146.   ".hqx",       "Binhex",
  147.   ".tar",       "Unix archive",
  148.   ".tex",       "Tex or LaTex document",
  149.   ".wav",       "Windows WAV audio",
  150.   ".c",         "C source",
  151.   ".pl",        "Perl source",
  152.   ".py",        "Python source",
  153.   ".tcl",       "TCL source",
  154.   ".??",        "unknown file type" );
  155. }
  156.  
  157.  
  158. #=====================================================================
  159. # END OF USER CONFIGURATION SECTION
  160. #=====================================================================
  161.  
  162.  
  163. #---------------------------------------------------------------------
  164. # PROCESS DATA FROM FORM
  165. #---------------------------------------------------------------------
  166.  
  167. &LocalReadParse;
  168.  
  169. $Keywords = $in{'keywords'};
  170. # allow only numbers, chars, whitespace, asterisks and parentheses
  171. $Keywords =~ s/[^\w()*\s]//g;    
  172.  
  173. $MaxHits = $in{'maxhits'};
  174. # remove anything not a number, or char in "all"
  175. $MaxHits =~ s/[^\dal]//g;
  176.     
  177. $IndexNumber = $in{'indexnumber'};
  178. # remove anything not a digit
  179. $IndexNumber =~ s/[^\d]//g;
  180.  
  181. $IndexData      = $in{'indexdata'};
  182. $SearchAll      = $in{'searchall'};
  183.  
  184. $Tags_Head      = $in{'head'};
  185. $Tags_Title      = $in{'title'};
  186. $Tags_Body      = $in{'body'};
  187. $Tags_Headings      = $in{'headings'};
  188. $Tags_Emphasized  = $in{'emphasized'};
  189. $Tags_Comments      = $in{'comments'};
  190.  
  191. $Tags = "";
  192. if ($Tags_Head)
  193. {
  194.   $Tags = $Tags."H";
  195. }
  196. if ($Tags_Title)
  197. {
  198.   $Tags = $Tags."t";
  199. }
  200. if ($Tags_Body)
  201. {
  202.   $Tags = $Tags."B";
  203. }
  204. if ($Tags_Headings)
  205. {
  206.   $Tags = $Tags."h";
  207. }
  208. if ($Tags_Emphasized)
  209. {
  210.   $Tags = $Tags."e";
  211. }
  212. if ($Tags_Comments)
  213. {
  214.   $Tags = $Tags."c";
  215. }
  216.  
  217.  
  218. if ($IndexNumber) 
  219. {
  220.   $IndexLocation = $MultiIndexLocation[$IndexNumber -1];
  221. }
  222. else
  223. {
  224.   $IndexLocation = $DefaultIndexLocation;
  225. }
  226.  
  227. # If the "Search entire files" box is checked, or when using a
  228. # simple form without any of the above variables, then search
  229. # everything by default.
  230.  
  231. if (($SearchAll) || 
  232.   (!$SearchAll 
  233.   && !$Tags_Head 
  234.   && !$Tags_Title 
  235.   && !$Tags_Body 
  236.   && !$Tags_Headings 
  237.   && !$Tags_Emphasized 
  238.   && !$Tags_Comments))
  239. {
  240.   $Tags = "";
  241. }
  242.  
  243. &SetupFileTypeDescriptions;
  244.  
  245. #---------------------------------------------------------------------
  246. # PRINT HTML PAGE FROM SEARCH RESULT
  247. #---------------------------------------------------------------------
  248.  
  249. print "Content-type: text/html\n\n"; 
  250. &PrintPageTop;
  251.  
  252. if (-e $SwishLocation)
  253. {
  254.   if (-x $SwishLocation)
  255.   {
  256.     # continue
  257.   }
  258.   else
  259.   {
  260.     print "<b>SWISH not executable by Web server</b>";
  261.     if ($ShowFilePaths)
  262.     {
  263.       print " - $SwishLocation";
  264.     }
  265.     print "\n";
  266.     &PrintPageEnd;
  267.     exit;
  268.   }
  269. }
  270. else
  271. {
  272.   print "<b>SWISH not found</b>";
  273.   if ($ShowFilePaths)
  274.   {
  275.     print " - $SwishLocation";
  276.   }
  277.   print "\n";
  278.   &PrintPageEnd;
  279.   exit;
  280. }
  281.  
  282. if ($Tags)
  283. {
  284.   if (open (SWISHOUT, "-|") || exec $SwishLocation,
  285.     "-w", split(/ /, $Keywords),
  286.     "-f", $IndexLocation,
  287.     "-m", $MaxHits,
  288.     "-t", $Tags)
  289.   {
  290.     &RunSearch;
  291.   }
  292. }
  293. else
  294. {
  295.   if (open (SWISHOUT, "-|") || exec $SwishLocation,
  296.     "-w", split(/ /, $Keywords),
  297.     "-f", $IndexLocation,
  298.     "-m", $MaxHits)
  299.   {
  300.     &RunSearch;
  301.   }
  302. }
  303.  
  304. &PrintPageEnd;
  305. exit;
  306.  
  307.  
  308. #---------------------------------------------------------------------
  309. # RUN SEARCH 
  310. #---------------------------------------------------------------------
  311.  
  312. sub RunSearch
  313. {
  314.   $ArrayIndex = 0;
  315.   $LineNumber = 1;
  316.   while ($LINE=<SWISHOUT>)
  317.   {
  318.     chop ($LINE);
  319.     $LineRecognized = 0;
  320.  
  321.     # the line may contain something other than a link
  322.     $LineRecognized = &ScanLineForIndexData;
  323.     if (!$LineRecognized)
  324.     {
  325.       $LineRecognized = &ScanLineForComments;
  326.       if (!$LineRecognized)
  327.       {
  328.     $LineRecognized = &ScanLineForErrorMessage;
  329.     if (!$LineRecognized)
  330.     {
  331.       $LineRecognized = &ScanLineForUsageReport;
  332.       if (!$LineRecognized)
  333.       {
  334.         # then otherwise the line contains a link
  335.         &ExtractLinkFromLine;
  336.         if ($score)
  337.         {
  338.               &AddLink;
  339.               $ArrayIndex ++;
  340.         }
  341.       }
  342.     }
  343.       }
  344.     }
  345.   }  
  346.   close (SWISHOUT);
  347.  
  348.   print "<blockquote>\n";
  349.   print "<dl>\n";
  350.  
  351.   $EndArrayIndex = @LinkArray;
  352.   for ($ArrayIndex = 0; $ArrayIndex < $EndArrayIndex; $ArrayIndex++)
  353.   {
  354.     $LiveFileExists = &CheckLink;
  355.     if ($LiveFileExists)
  356.     {
  357.       &PrintLink;
  358.     }
  359.   }
  360.  
  361.   print "</dl>\n";
  362.   print "</blockquote>\n";
  363.  
  364.   # if "show data about index" box is checked on HTML form
  365.   if ($IndexData)
  366.   {  
  367.     &PrintIndexData;
  368.   }
  369. }
  370.  
  371.  
  372. #--------------------------------------------------------------
  373. # SCAN LINE FOR INDEX DATA 
  374. #--------------------------------------------------------------
  375.  
  376. sub ScanLineForIndexData
  377. {
  378.   $ReturnValue = 0;
  379.  
  380.   if ($LINE =~ /^# SWISH/) 
  381.   {
  382.     ($junk, $iformat) = split(/format/,$LINE,2);
  383.     $ReturnValue = 1;
  384.   }
  385.   else
  386.   {
  387.     if ($LINE =~ /^# Name:/) 
  388.     {
  389.       ($junk, $iname) = split(/:/,$LINE,2);
  390.       $ReturnValue = 1;
  391.     }
  392.     else
  393.     {
  394.       if ($LINE =~ /^# Saved as:/) 
  395.       {
  396.     ($junk, $ifilename) = split(/:/,$LINE,2);
  397.     $ReturnValue = 1;
  398.       }
  399.       else
  400.       {
  401.     if ($LINE =~ /^# Indexed on:/) 
  402.     {
  403.       ($junk, $idate) = split(/:/,$LINE,2);
  404.       $ReturnValue = 1;
  405.     }
  406.     else
  407.     {
  408.       if ($LINE =~ /^# Maintained by:/) 
  409.       {
  410.         ($junk, $imaintby) = split(/:/,$LINE,2);
  411.         $ReturnValue = 1;
  412.       }
  413.       else
  414.       {
  415.         if ($LINE =~ /^# Description:/) 
  416.         {
  417.           ($junk, $idesc) = split(/:/,$LINE,2);
  418.           $ReturnValue = 1;
  419.         }
  420.         else
  421.         {
  422.           if ($LINE =~ /^# Counts:/) 
  423.           {
  424.         ($junk, $icounts) = split(/:/,$LINE,2);
  425.         $ReturnValue = 1;
  426.           }
  427.         }
  428.       }
  429.     }
  430.       }
  431.     }
  432.   }
  433.   return ($ReturnValue);
  434. }                
  435.  
  436.  
  437. #--------------------------------------------------------------
  438. # SCAN LINE FOR COMMENTS 
  439. #--------------------------------------------------------------
  440.  
  441. sub ScanLineForComments
  442. {
  443.   $ReturnValue = 0;
  444.  
  445.   # skip remaining lines with #, "search words", and "."        
  446.   if ($LINE =~ /^#/)        
  447.   { 
  448.     $ReturnValue = 1;
  449.   }
  450.   else
  451.   {
  452.     if ($LINE =~ /^search/) 
  453.     { 
  454.       $ReturnValue = 1;
  455.     }
  456.     else
  457.     {
  458.       if ($LINE =~ /^\./)        
  459.       { 
  460.     $ReturnValue = 1;
  461.       }
  462.     }
  463.   }
  464.   return ($ReturnValue);
  465. }
  466.                 
  467.  
  468. #--------------------------------------------------------------
  469. # SCAN LINE FOR ERROR MESSAGE 
  470. #--------------------------------------------------------------
  471.  
  472. sub ScanLineForErrorMessage
  473. {
  474.   $ReturnValue = 0;
  475.  
  476.   # if there is an error message, output it 
  477.   # (swish error messages start with err:)
  478.   if ($LINE =~ /^err:/) 
  479.   {
  480.     ($err, $message) = split(/:/,$LINE,2);
  481.     print "<dt><dd>"; 
  482.     print "<b>$message</b><br>"; 
  483.     print "</dd>\n"; 
  484.     $ReturnValue = 1;
  485.   }
  486.  
  487.   return ($ReturnValue);
  488. }
  489.  
  490.  
  491. #--------------------------------------------------------------
  492. # SCAN LINE FOR USAGE REPORT 
  493. #--------------------------------------------------------------
  494.  
  495. sub ScanLineForUsageReport
  496. {
  497.   $ReturnValue = 0;
  498.  
  499.   # Swish reports its usage if called incorrectly.
  500.   # If so, print the message.
  501.   if ($LINE =~ /  usage:/) 
  502.   {
  503.     print "<dt><dd>"; 
  504.     print "<p><b>An error occured when calling Swish:</b><br>";
  505.     print "<p>$SwishLocation -w $Keywords -f $IndexLocation -m $MaxHits -t $Tags<br>";
  506.     print "<p>Swish returned:";
  507.     print "<p><pre>";
  508.     print "$LINE";
  509.     while ($LINE=<SWISHOUT>) 
  510.     { 
  511.       print "$LINE\n"; 
  512.     }
  513.     print "</pre>";
  514.     print "</dd>"; 
  515.  
  516.     $ReturnValue = 1;
  517.   }
  518.   return ($ReturnValue);
  519. }
  520.  
  521.  
  522. #--------------------------------------------------------------
  523. # EXTRACT LINK FROM LINE
  524. #--------------------------------------------------------------
  525.  
  526. sub ExtractLinkFromLine
  527. {
  528.   # extract the four elements of a good search result line 
  529.   # (Thanks to Ian Phillips & Joshua Sean Bell)
  530.  
  531.   ($score, $link, $title, $bytes) = 
  532.   ($LINE =~ m/^(\d+)\s+(\S+)\s+"([^\"]+)"\s+(\d+)\s*$/);
  533.  
  534.   # get the mime type for the file extension
  535.  
  536.   ($ext = "\L$1\E" || ".??") if ($link =~ /(\.\w+)$/);
  537.   $filetype = $mimetype{$ext} || $mimetype{".??"} ;
  538. }
  539.  
  540.  
  541. #---------------------------------------------------------------------
  542. # ADD LINK TO ARRAY
  543. #---------------------------------------------------------------------
  544.  
  545. sub AddLink
  546. {
  547.   $LinkArray[$ArrayIndex]        = $link;
  548.   $TitleArray[$ArrayIndex]       = $title;
  549.   $ScoreArray[$ArrayIndex]       = $score;
  550.   $BytesArray[$ArrayIndex]       = $bytes;
  551.   $FileModDateArray[$ArrayIndex] = "";
  552.   $FileModTimeArray[$ArrayIndex] = "";
  553.   $ExtArray[$ArrayIndex]         = $ext;
  554.   $FileTypeArray[$ArrayIndex]    = $filetype;
  555. }
  556.  
  557.  
  558. #---------------------------------------------------------------------
  559. # PRINT LINK
  560. #---------------------------------------------------------------------
  561.  
  562. sub PrintLink
  563. {
  564.   print "<p>\n";
  565.   print "<dt><b>$LineNumber. <a href=\"$LinkArray[$ArrayIndex]\">$TitleArray[$ArrayIndex]</a></b>\n";
  566.   if ($HotlinkURLs)
  567.   {
  568.     print "<dd><a href=\"$LinkArray[$ArrayIndex]\">$LinkArray[$ArrayIndex]</a>\n";
  569.   }
  570.   else
  571.   {
  572.     print "<dd>$LinkArray[$ArrayIndex]\n";
  573.   }
  574.   print "<dd><b>$ScoreArray[$ArrayIndex]</b> score, ";
  575.   print "$BytesArray[$ArrayIndex] bytes, ";
  576.   print "$FileModDateArray[$ArrayIndex] $FileModTimeArray[$ArrayIndex]";
  577.   if ($FileTypeArray[$ArrayIndex] != " ") 
  578.   {  
  579.     print " - $FileTypeArray[$ArrayIndex]";
  580.   }
  581.   print "\n";
  582.   $LineNumber ++;
  583. }
  584.  
  585.  
  586. sub CheckLink
  587. {
  588.   $LiveFileFound = 0;
  589.  
  590.   $FileName = $LinkArray[$ArrayIndex];
  591.   $FileName =~ s#$BaseURL##;
  592.   $FileSpec = $BaseDirectory.$FileName;
  593.  
  594.   if (-e $FileSpec)
  595.   {
  596.     $LiveFileFound = 1;
  597.     &GetFileStats;
  598.     $BytesArray[$ArrayIndex]       = $ShortFileSize;
  599.     $FileModDateArray[$ArrayIndex] = $FileModDate;
  600.     $FileModTimeArray[$ArrayIndex] = $FileModTime;
  601.   }
  602.   return ($LiveFileFound); 
  603. }
  604.  
  605.  
  606. #----------------------------------------------------------------
  607. # Get File Stats
  608. #----------------------------------------------------------------
  609.  
  610. sub GetFileStats
  611. {
  612.   ( $Device, 
  613.     $Inode, 
  614.     $FilePerms, 
  615.     $NumHardLinks, 
  616.     $Uid, 
  617.     $Gid, 
  618.     $DeviceType, 
  619.     $FileSize, 
  620.     $AccessedTime, 
  621.     $ModifiedTime, 
  622.     %DontCare) 
  623.   = stat($FileSpec);
  624.  
  625.   if ($FileSize < $HugeFileSize)
  626.   {
  627.     $ShortFileSize = $FileSize;
  628.     while (length ($FileSize) < length ($HugeFileSize))
  629.     {
  630.       $FileSize = $Zero.$FileSize;
  631.     }
  632.   }
  633.  
  634.   if ($ModifiedTime < $HugeTime)
  635.   {
  636.     while (length ($ModifiedTime) < length ($HugeTime))
  637.     {
  638.       $ModifiedTime = $Zero.$ModifiedTime;
  639.     }
  640.   }
  641.  
  642.   ( $Seconds, 
  643.     $Minutes, 
  644.     $HourNum, 
  645.     $MonthDay, 
  646.     $MonthNum, 
  647.     $Year, 
  648.     $WeekdayNum, 
  649.     $YeardayNum,
  650.     $DSTFlag) 
  651.   = localtime ($ModifiedTime);
  652.  
  653.   %MonthWord = 
  654.   (0, "Jan", 
  655.     1, "Feb", 
  656.     2, "Mar", 
  657.     3, "Apr", 
  658.     4, "May", 
  659.     5, "Jun", 
  660.     6, "Jul", 
  661.     7, "Aug", 
  662.     8, "Sep", 
  663.     9, "Oct", 
  664.     10, "Nov", 
  665.     11, "Dec");
  666.  
  667.   $FileModDate = "$MonthWord{$MonthNum} $MonthDay '$Year";
  668.  
  669.   if ($Minutes < 10)
  670.   {
  671.     $FileModTime = "$HourNum:$Zero$Minutes";
  672.   }
  673.   else
  674.   {
  675.     $FileModTime = "$HourNum:$Minutes";
  676.   }
  677. }
  678.  
  679.  
  680. #---------------------------------------------------------------------
  681. # PRINT INDEX DATA
  682. #---------------------------------------------------------------------
  683.  
  684. sub PrintIndexData
  685. {
  686.   if (!$Keywords) 
  687.   {
  688.     &SearchFileForIndexData;
  689.   }
  690.   print "<hr>";
  691.   print "<blockquote>\n";
  692.   print "Index name: <b>$iname</b><br>\n";
  693.   print "Description: <b>$idesc</b><br>\n";
  694.   print "Index contains: <b>$icounts</b><br>\n";
  695.   if ($ShowFilePaths)
  696.   {
  697.     print "Location: <b>$IndexLocation</b><br>\n";
  698.     print "Saved as (internal name): <b>$ifilename</b><br>\n";
  699.   }
  700.   print "SWISH Format: <b>$iformat</b><br>\n";
  701.   print "Maintained by: <b>$imaintby</b><br>\n";
  702.   print "Indexed on: (day/month/year): <b>$idate</b><br>\n";
  703.   if (open (SWISHOUT, "-|") || exec $SwishLocation, "-V")
  704.   {
  705.     $SwishVersion = <SWISHOUT>;
  706.     close (SWISHOUT);
  707.     print "Searched with: <b>$SwishVersion</b><br>\n";
  708.   }
  709.   print "</blockquote>\n";
  710. }
  711.  
  712.  
  713. #---------------------------------------------------------------------
  714. # SEARCH FILE FOR INDEX DATA
  715. #---------------------------------------------------------------------
  716.  
  717. # If the form's input field is blank, ordinarily no search is made,
  718. # which prevents reading the index file for the index data. In that 
  719. # case, the following subroutine is called.
  720.  
  721. sub SearchFileForIndexData
  722. {
  723.   # use a keyword that definitely won't be found
  724.   $Keywords = $GoofyKeyword;
  725.   if (open (SWISHOUT, "-|") || exec $SwishLocation, 
  726.     "-f", $IndexLocation,
  727.     "-w", $Keywords)
  728.   {
  729.     while ($LINE=<SWISHOUT>)
  730.     {
  731.       chop ($LINE);
  732.       &ScanLineForIndexData;
  733.     }
  734.     close (SWISHOUT);
  735.   }
  736. }
  737.  
  738.  
  739. #=====================================================================
  740. # GENERAL PURPOSE (BOILERPLATE) ROUTINES 
  741. #=====================================================================
  742.  
  743. sub LocalReadParse
  744. # from Steven Brenner's cgi-lib.pl v1.14
  745. {
  746.   local (*in) = @_ if @_;
  747.   local ($i, $key, $val);
  748.  
  749.   # Read in text
  750.   if (&LocalMethGet) 
  751.   {
  752.     $in = $ENV{'QUERY_STRING'};
  753.   } 
  754.   elsif (&LocalMethPost) 
  755.   {
  756.     read(STDIN,$in,$ENV{'CONTENT_LENGTH'});
  757.   }
  758.  
  759.   @in = split(/[&;]/,$in); 
  760.  
  761.   foreach $i (0 .. $#in) 
  762.   {
  763.     # Convert plusses to spaces
  764.     $in[$i] =~ s/\+/ /g;
  765.  
  766.     # Split into key and value
  767.     # splits on the first =
  768.     ($key, $val) = split(/=/,$in[$i],2); 
  769.  
  770.     # Convert %XX from hex numbers to alphanumeric
  771.     $key =~ s/%(..)/pack("c",hex($1))/ge;
  772.     $val =~ s/%(..)/pack("c",hex($1))/ge;
  773.  
  774.     # Associate key and value 
  775.     # \0 is the multiple separator
  776.     $in{$key} .= "\0" if (defined($in{$key})); 
  777.     $in{$key} .= $val;
  778.   }
  779.   return scalar(@in); 
  780. }
  781.  
  782. sub LocalMethGet 
  783. # from Steven Brenner's cgi-lib.pl v1.14
  784. # true if this cgi call was using the GET request, false otherwise
  785. {
  786.   return ($ENV{'REQUEST_METHOD'} eq "GET");
  787. }
  788.  
  789. sub LocalMethPost 
  790. # from Steven Brenner's cgi-lib.pl v1.14
  791. # true if this cgi call was using the POST request, false otherwise
  792. {
  793.   return ($ENV{'REQUEST_METHOD'} eq "POST");
  794. }
  795.